﻿using System.Globalization;
using BlogsAPI.LivejournalRPC;
using BlogsAPI.Rdf;
using CookComputing.XmlRpc;
using Newtonsoft.Json.Linq;

namespace BlogsAPI.Sites
{
    using System;
    using System.IO;
    using System.Collections.Generic;
    using System.Text;
    using System.Net;
    using System.Web;
    using System.Text.RegularExpressions;
    using System.Security.Cryptography;
    using Abstract;
    using Interfaces;
    using System.Diagnostics;
    using System.Threading;
    using System.Xml;
    using RssToolkit.Rss;

    /// <summary>
    /// Живой Журнал, 
    /// </summary>
    /// <seealso cref="http://lj.ru"/>
    [BlogServiceAPI(Description = "Живой Журнал", Link = "https://www.livejournal.com")]
    public class Livejournal : BlogServer, IPosts, IComments, IFriends, IOpenIdServer, IQuote
    {
        private static readonly Regex Validation = new Regex(@"^https?://(?:[-_\w]+\.)?livejournal\.com", Regexoptions);
        private static readonly Regex ValidationFull = new Regex(@"^https?://(?:([-_\w]+)\.)?livejournal\.com(?:/read)?(?:[/=](.*?)){0,2}(?:/|$)", Regexoptions);
        
        private static readonly Regex eljFormAuth = new Regex(@"name.{2}lj_form_auth\W[^>]*?value\W{2}([^'""]*)\W", Regexoptions);
        private static readonly Regex eSessionless = new Regex(@"sessionless\W+([^""]+)", Regexoptions);
        //private static readonly Regex eServerTime = new Regex(@"first_timepost\W+(\d+)\D", Regexoptions);
        private static readonly Regex readers = new Regex(@"commafy_count[^}]+?(\d\s?[\d,]+)\W([^{}]+)friendof", Regexoptions);
        //<li class="b-xylem-cell b-xylem-cell-amount">    158 comments    </li> 
        private static readonly Regex comms = new Regex(@"<[^>]+amount[^>]+>\s*(\d+)\s+comments[^<]*</", Regexoptions);
        private static readonly Regex rObject = new Regex(@"(?:<lj\-embed>\s*)?(<object\s.*?</object>)(?:\s*</lj\-embed>)?", Regexoptions);

        /// <summary>
        /// Извлечение идентификационного параметра формы
        /// </summary>
        /// <param name="page">страница сайта</param>
        /// <returns></returns>
        private string GetFormAuth(string page)
        {
            //lj_form_auth
            Match m = eljFormAuth.Match(page);
            if (!m.Success)
            {
                return "";
                //throw new Exception("Не найден номер lj_form_auth");
            }
            return m.Groups[1].ToString();
        }

        #region interface: BlogServer

        [DebuggerStepThrough]
        public Livejournal()
        {
            Encoding = Encoding.UTF8;
        }

        /// <summary>
        /// http://www.t30p.ru/stats.aspx
        /// </summary>
        public override bool HasRating
        {
            get { return true; }
        }

        /// <summary>
        /// проверка, является ли передаваемый урл чатью этого сервиса
        /// </summary>
        public override Boolean ValidateLink(String sLink)
        {
            return Validation.Match(sLink).Success;
        }

        /// <summary>
        /// проверка, является ли передаваемый урл чатью этого сервиса
        /// </summary>
        /// <param name="sLink">ссылка для проверки</param>
        /// <param name="userName">Имя пользователя на блогохостинге</param>
        /// <param name="bType">Тип блога - пользователь или сообщество</param>
        public override Boolean ValidateLink(String sLink, out String userName,out BlogType bType)
        {
            bType = BlogType.Unknown;
            userName = String.Empty;
            Match m = ValidationFull.Match(sLink);
            if (m.Success)
            {
                try
                {
                    if (String.IsNullOrEmpty(m.Groups[1].ToString())
                        || String.Compare(m.Groups[1].ToString(), "www", true) == 0
                        || String.Compare(m.Groups[1].ToString(), "m", true) == 0)//мобильная версия
                    {
                        //специальная вставка, чтобы отсеять QOTD
                        if (!m.Groups[2].Captures[0].ToString().StartsWith("user") // "users" or "user"
                            && String.Compare(m.Groups[2].Captures[0].ToString(), "community") != 0)
                        {
                            return false;
                        }
                        //www.livejournal.com/users/tema
                        bType = m.Groups[2].Captures[0].ToString().StartsWith("user")
                            ? BlogType.User : BlogType.Community;
                        userName = m.Groups[2].Captures[1].ToString();
                    }
                    else if (String.Compare(m.Groups[1].ToString(), "community", true) == 0)
                    {
                        //community.livejournal.com/ru_sex
                        bType = BlogType.Community;
                        userName = m.Groups[2].Captures[0].Value;
                    }
                    else if (String.Compare(m.Groups[1].ToString(), "users", true) == 0)
                    {
                        //users.livejournal.com/tema
                        bType = BlogType.User;
                        userName = m.Groups[2].Captures[0].Value;
                    }
                    else
                    {
                        //tema.livejournal.com
                        bType = BlogType.User;
                        userName = m.Groups[1].ToString();
                    }
                    userName = userName.Replace("-", "_");
                }catch
                {
                    
                }
            }
            else
            {
                userName = String.Empty;
            }
            return m.Success;
        }

        /// <summary>
        /// Получение ссылки на блог блогера
        /// </summary>
        /// <param name="userName">ник блогера</param>
        /// <param name="btype">Тип блога - пользователь или сообщество</param>
        public override String GetBlogLink(string userName, BlogType btype)
        {
            if (btype == BlogType.Community)
            {
                return String.Format("https://community.livejournal.com/{0}", userName);
            }
            //может быть varlamov.ru
            return userName.StartsWith("_") ? String.Format("https://users.livejournal.com/{0}", userName) : String.Format("https://{0}{1}", userName, userName.Contains(".ru")?"": ".livejournal.com");
        }

        /// <summary>
        /// Формирование HTML кода для отображения имени пользователя
        /// </summary>
        /// <param name="userName">ник блогера</param>
        /// <param name="bt">Тип блога - пользователь или сообщество</param>
        /// <returns>HTML</returns>
        public override String GetUsernameHtml(string userName, BlogType bt)
        {
            return String.Format("<span class='ljuser' lj:user='{0}' style='white-space: nowrap;'>"+
                "<a href='{1}'><img src='//blob.t30p.ru/img/{2}.gif' alt='{0}' width='17' height='17' style='vertical-align: bottom; border: 0;' /></a>" +
                "<a href=\"{3}\"><b>{0}</b></a></span>",
                userName,GetBlogLink(userName,bt)+"/profile", bt== BlogType.Community?"community":"userinfo",
                GetBlogLink(userName, bt));
        }

        /// <summary>
        /// Формирование HTML кода для отображения имени пользователя
        /// </summary>
        /// <param name="userName">ник блогера</param>
        /// <param name="bt">Тип блога - пользователь или сообщество</param>
        /// <returns>HTML</returns>
        public override String GetUsernameHtmlSelf(string userName, BlogType bt)
        {
            return String.Format("<lj user=\"{0}\">", userName);
        }

        /// <summary>
        /// Определение числа читателей блога
        /// </summary>
        /// <param name="username">имя</param>
        /// <param name="bt">тип</param>
        /// <returns></returns>
        public override uint? HowManyReaders(string username, BlogType bt)
        {
            try
            {
                String blogname = GetBlogLink(username, bt);
                HttpWebRequest myHttpWebRequest = MakeRequest(blogname+"/profile");
                myHttpWebRequest.Method = "GET"; // метод GET
                myHttpWebRequest.Referer = blogname;
                myHttpWebRequest.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;
                //получаем ответ и его разбираем...
                var myHttpWebResponse = (HttpWebResponse)myHttpWebRequest.GetResponse();
                string result = new StreamReader(myHttpWebResponse.GetResponseStream(), Encoding).ReadToEnd();
                myHttpWebResponse.Close();
                //ПОЛУЧИЛИ xml - откроемка его...
                Match mc = readers.Match(result);
                if(mc.Success)
                {
                    return uint.Parse(mc.Groups[1].Value.Replace(",",""));//берем последнее, так как оно отвечает за просто друзей
                }
            }
            catch (Exception e1)
            {
                Debug.WriteLine("Ошибка загрузки числа читателей: " + e1.Message);
            }
            return null;
        }

        /// <summary>
        /// Определение числа комментариев к записи
        /// </summary>
        /// <param name="bp">Пост для которого считаем комменты</param>
        /// <returns>Число комментариев к посту</returns>
        public override int HowManyComments(BlogPost bp)
        {
            string html = string.Empty;
            return HowManyComments(bp, ref html);
        }

        /// <summary>
        /// Определение числа комментариев к записи
        /// </summary>
        /// <param name="bp">Пост для которого считаем комменты</param>
        /// <returns>Число комментариев к посту</returns>
        public int HowManyComments(BlogPost bp, ref string Html)
        {
            int iRet = 0; 
            try
            {
                sCookie = "adult_concepts=1; adult_explicit=1;";
                HttpWebRequest myHttpWebRequest = MakeRequest(bp.Link.OriginalString+
                    (bp.Link.OriginalString.Contains("?")?"":"?format=light"));
                myHttpWebRequest.Method = "GET";
                //myHttpWebRequest.AllowAutoRedirect = false;
                myHttpWebRequest.Referer = bp.Link.OriginalString;
                HttpWebResponse resp = (HttpWebResponse) myHttpWebRequest.GetResponse();
                Html = new StreamReader(resp.GetResponseStream()).ReadToEnd();
                resp.Close(); //закроем поток(!)

                //считаем число комментариев
                Match m = comms.Match(Html);
                if (m.Success)
                {
                    iRet = int.Parse(m.Groups[1].Value);
                }
            }
            catch (Exception e1)
            {
                Log("LiveJournal GetCommentsCount failed: " + e1.Message + " "+bp.Link.OriginalString);
            }
            return iRet;
        }

        #endregion

        #region interface: IPosts

        /// <summary>
        /// Получение списка последнних записей
        /// </summary>
        /// <returns></returns>
        public List<BlogPost> GetLatest()
        {
            var oRet = new List<BlogPost>();
            try
            {
                const string mainpage = "https://www.livejournal.com/latest";
                const string apicont = "https://l-api.livejournal.com/__api/";
                
                HttpWebRequest myHttpWebRequest = MakeRequest(mainpage);
                myHttpWebRequest.Method = "GET"; // метод GET
                myHttpWebRequest.Referer = "https://www.livejournal.com";
                //получаем ответ и его разбираем...
                var myHttpWebResponse = (HttpWebResponse)myHttpWebRequest.GetResponse();
                string result = new StreamReader(myHttpWebResponse.GetResponseStream(), Encoding).ReadToEnd();
                myHttpWebResponse.Close();
                string sessionid = eSessionless.Match(result).Groups[1].Value;
                var lastposttime = Common.ConvertToUnixTimestamp(DateTime.UtcNow.AddMinutes(-30)); 
                    //eServerTime.Match(result).Groups[1].Value;
                /////////////////////////
                int id = int.Parse(DateTime.Now.ToString("HHmmss"));
                HashSet<string> links = new HashSet<string>();
                for (int i = id; i < id + 3; i++)
                {
                    string sQueryString3 = @"{""jsonrpc"":""2.0"",""method"":""latest.get_entries"",""params"":{""first_timepost"":"+ lastposttime + @"},""id"":8108603939}";
                    //////////////////////////
                    //string sQueryString2 =
                    //    @"{""jsonrpc"":""2.0"",""method"":""latest.get_entries"",""params"":{""last_timepost"":" +
                    //    lastposttime +
                    //    @",""random_timestamp"":"+
                    //    (lastposttime + DateTime.Now.Second + DateTime.Now.Minute)
                    //    +@"},""id"":1388167200000}";

                        //"http://l-api.livejournal.com/__api/?callback=jQuery1388167200000latest__get_entries&request=%7B%22jsonrpc%22%3A%222.0%22%2C%22method%22%3A%22latest.get_entries%22%2C%22params%22%3A%7B%22last_timepost%22%3A1388167940%2C%22random_timestamp%22%3A1388153640%7D%2C%22id%22%3A1388167200000%7D";
                    myHttpWebRequest = MakeRequest(apicont + "?request=" + HttpUtility.UrlEncode(sQueryString3));
                    myHttpWebRequest.Method = "GET"; // метод GET
                    myHttpWebRequest.Referer = mainpage;

                    //byte[] byteArr = _encoding.GetBytes(sQueryString3);
                    //myHttpWebRequest.ContentLength = byteArr.Length;
                    //myHttpWebRequest.GetRequestStream().Write(byteArr, 0, byteArr.Length);
                    //получаем ответ и его разбираем...
                    myHttpWebResponse = (HttpWebResponse) myHttpWebRequest.GetResponse();
                    result = new StreamReader(myHttpWebResponse.GetResponseStream(), Encoding).ReadToEnd();
                    myHttpWebResponse.Close();
                    JObject oData = JObject.Parse(result);
                    if (oData["result"]["status"].Value<string>() == "no")
                    {
                        continue;
                    }
                    foreach (JToken jMsg in oData["result"]["params"]["recent"])
                    {
                        BlogPost bp = BlogPost.SimpleLink(jMsg["url"].Value<string>());
                        if (links.Add(bp.Link.OriginalString))
                        {
                            bp.Comments = 0;
                            bp.Links = 0;
                            bp.Body = jMsg["body"].Value<string>();
                            bp.Subject = jMsg["subject"].Value<string>();
                            if (!DateTime.TryParseExact(jMsg["time"].Value<string>(), "MMM d HH:mm",
                                new CultureInfo("en-US"), DateTimeStyles.AssumeUniversal, out bp.Published))
                            {
                                bp.Published = DateTime.Now;
                            }
                            oRet.Add(bp);
                        }
                    }
                    lastposttime = oData["result"]["params"]["last_timepost"].Value<long>();
                }
            }catch(Exception e1)
            {
                Debug.Write(e1);
            }
            return oRet;
        }

        /// <summary>
        /// Обрабатываем пост в соответствии с требованиями блогохостинга
        /// перед его публикацией куда-нить.
        /// </summary>
        /// <param name="bp"></param>
        /// <returns></returns>
        /// <remarks>в Наши задачи входит окаймить object тэгом <lj-embed></remarks>
        public override BlogPost PreparePost(BlogPost bp)
        {
            
            bp.Body = rObject.Replace(bp.Body,"<lj-embed>$1</lj-embed>");
            if (bp.Subject.Length > 255) bp.Subject = bp.Subject.Substring(0, 255);
            return base.PreparePost(bp);
        }

        /// <summary>
        /// Выкладывание записи в блоге
        /// </summary>
        /// <param name="user">Аккаунт пользователя, который делает пост</param>
        /// <param name="bp">пост для блога</param>
        /// <returns></returns>
        public override PostResult MakePost(UserAccount user, BlogPost bp)
        {
            PostResult ps = new PostResult {Error = new NotImplementedException()};
            try
            {
                //внесем в пост необходимые коррективы
                bp = PreparePost(bp);
                //если идет постинг в сообщество, то нужно проверить вступили ли мы в него
                if(!String.IsNullOrEmpty(bp.SpecialParam))
                {
                    if(IsFriended(bp.SpecialParam,BlogType.Community,user.username).Count==0)
                    {
                        //вступаем в сообщество
                        Exception joinerr = JoinCommunnity(user, bp.SpecialParam);
                        if(joinerr!=null)
                        {
                            throw joinerr;
                        }
                    }
                }

                //Ниже идет сам процесс запощивания
                #region Старый метод влоб

                /*            
                 HttpWebRequest myHttpWebRequest = MakeRequest("http://www.livejournal.com/update.bml");
                myHttpWebRequest.Method = "GET";
                myHttpWebRequest.Referer = "http://www.livejournal.com/";
                ////
                HttpWebResponse myHttpWebResponse = (HttpWebResponse)myHttpWebRequest.GetResponse();
                //получаем ответ
                string result = new StreamReader(myHttpWebResponse.GetResponseStream(), Encoding).ReadToEnd();
                myHttpWebResponse.Close();

                if (!String.IsNullOrEmpty(myHttpWebResponse.Headers[HttpResponseHeader.SetCookie]))
                {
                    CookieParse(myHttpWebResponse.Headers[HttpResponseHeader.SetCookie]);
                }

                Regex eChal = new Regex(@"name.{2}chal\W[^>]*value\W{2}([^']*)'", Regexoptions);
                Match m = eChal.Match(result);
                if (!m.Success)
                {
                    Log("Попытка сделать пост не удалась, не найден номер CHAL");
                    throw new Exception("No `Chal` param was found!");
                }
                if(String.IsNullOrEmpty(sCookie))
                {
                    //это произвольная величина, специально для ЖЖ
                    sCookie = "ljuniq=vnCxHnBtdpkZj0M%3A1315949963%3Apgstats0; rsi_segs=; ljlive-bubble=2;";
                }
                //making post here
                //sCookie = "";
                myHttpWebRequest = MakeRequest("http://www.livejournal.com/update.bml");
                myHttpWebRequest.Method = "POST";
                myHttpWebRequest.Referer = "http://www.livejournal.com/update.bml";
                myHttpWebRequest.AllowAutoRedirect = false;
                myHttpWebRequest.ContentType = "application/x-www-form-urlencoded";
                // передаем параметры
                string sQueryString = String.Format("subject={0}&event={1}&prop_taglist={2}&prop_current_mood={3}&"+
                    "prop_current_music={4}&prop_current_location={5}&event_format=preformatted&user={6}&password={7}&"+
                    "lj_form_auth={8}&chal={9}&security={10}&usejournal={11}",
                    bp.SubjectUrlEnc,
                    bp.BodyUrlEnc,
                    HttpUtility.UrlEncode(bp.GetParam(PostParams.Tags).ToString()),
                    HttpUtility.UrlEncode(bp.GetParam(PostParams.Mood).ToString()),
                    HttpUtility.UrlEncode(bp.GetParam(PostParams.Music).ToString()),
                    HttpUtility.UrlEncode(bp.GetParam(PostParams.Location).ToString()),
                    user.username,user.password, // 7й параметр
                    GetFormAuth(result), m.Groups[1].Value,
                    GetPublicLevel(bp.Type), String.IsNullOrEmpty(bp.SpecialParam)?user.username:bp.SpecialParam);
                //////
                //	$response = md5(m.Groups[1].ToString().md5($pass));
                sQueryString += String.Format("&timezone=400&custom_time=0&response={0}&prop_picture_keyword=&switched_rte_on=0&comment_settings=" +
                    "&prop_opt_screening=&action:update=Post+to+{1}", 
                    MakePwdMd5(user.password, m.Groups[1].ToString()), 
                    String.IsNullOrEmpty(bp.SpecialParam) ? user.username : bp.SpecialParam);
                //но это еще не все, теперь надо добавить дату поста, если она менялась или еще что....
                DateTime posttime = String.IsNullOrEmpty(bp.GetParam(PostParams.Date).ToString())?DateTime.Now:(DateTime)bp.GetParam(PostParams.Date);
                sQueryString += String.Format("&date_diff={0}&date_diff_nojs={0}&prop_opt_backdated={0}&date_ymd_dd={1}&date_ymd_mm={2}&date_ymd_yyyy={3}"+
                        "&hour={4}&min={5}", 
                        String.IsNullOrEmpty(bp.GetParam(PostParams.Date).ToString()) ? 0 : 1,
                        posttime.Day, posttime.Month, posttime.Year, posttime.Hour, posttime.Minute);
                 
                byte[] byteArr = _encoding.GetBytes(sQueryString);
                myHttpWebRequest.ContentLength = byteArr.Length;
                myHttpWebRequest.GetRequestStream().Write(byteArr, 0, byteArr.Length);

                myHttpWebResponse = (HttpWebResponse)myHttpWebRequest.GetResponse();
                //получаем ответ
                result = new StreamReader(myHttpWebResponse.GetResponseStream(), Encoding).ReadToEnd();
                myHttpWebResponse.Close();

                Regex gettinglink = new Regex(@"<li>\s*<a href\W{2}(http://[^\.]+\.livejournal\.com[^""'0-9]*[0-9]*\.html)""", Regexoptions);
                m = gettinglink.Match(result);
                if (m.Success)
                {
                    ps.sLink = new Uri(m.Groups[1].ToString());
                    ps.Error = null;
                    bp.Existance = true;
                }
                else
                {
                    ps.Error = new Exception("Попытка сделать пост не удалась, не найдена ссылка на пост");
                    Log(ps.Error.Message);
                    return ps;
                }  */
#endregion
                
                ILj proxy = XmlRpcProxyGen.Create<ILj>();
                //if(bp.Published==null || bp.Published == DateTime.MinValue)
                //{
                bp.Published = DateTime.UtcNow.AddHours(3);//время московское выставили
                //}
                PostLj ljPost = new PostLj
                                    {
                                        username = user.username,
                                        password = user.password,
                                        day = bp.Published.Day,
                                        mon = bp.Published.Month,
                                        min = bp.Published.Minute,
                                        hour = bp.Published.Hour,
                                        year = bp.Published.Year
                                    };
                ljPost.usejournal = String.IsNullOrEmpty(bp.SpecialParam) ? ljPost.username : bp.SpecialParam;
                ljPost.security = GetPublicLevel(bp.Type);
                ljPost.subject = bp.Subject;
                ljPost.@event = bp.Body;
                ljPost.props = new AttributesLj
                                   {
                                       taglist = bp.GetParam(PostParams.Tags).ToString(),
                                       current_mood = bp.GetParam(PostParams.Mood).ToString(),
                                       current_music = bp.GetParam(PostParams.Music).ToString(),
                                       current_location = bp.GetParam(PostParams.Location).ToString(),
                                       opt_preformatted = true
                                   };
                PostLjAnswer oResponse = proxy.Post(ljPost);
                if(Uri.TryCreate(oResponse.url,UriKind.Absolute,out ps.sLink))
                {
                    //успешно запостились
                    bp.Existance = true;
                    ps.Error = null;
                }
            }
            catch (Exception we)
            {
                Log("MakePost WebError: " + we.Message);
                ps.Error = we;
            }
            //
            return ps;
        }

        private static string GetPublicLevel(PostType tp)
        {
            switch (tp)
            {
                case PostType.Private:
                    return "private";
                case PostType.FriendsOnly:
                    return "friends";
                default:
                    return "public";
            }
        }

        /// <summary>
        /// Выкладывание записи в блоге
        /// </summary>
        /// <param name="user">Аккаунт пользователя, делающего коммент</param>
        /// <param name="bp">коммент для блога</param>
        /// <returns></returns>
        public override PostResult MakeComment(UserAccount user, CommentPost bp)
        {
            PostResult ps = new PostResult {Error = new NotImplementedException()};
            try
            {
                if (bp.Link==null)
                {
                    throw new Exception("Не задана ссылка на пост для комментирования");
                }
                if (!ValidateLink(bp.Link.OriginalString))
                {
                    throw new Exception("Can't comment on " + bp.Link.OriginalString);
                }
                
                //1) проверим, что ссылка содержит номер поста
                Regex rItemID = new Regex(@"/([0-9]+)\.html$",Regexoptions);
                Match m = rItemID.Match(bp.Link.ToString());
                if (!m.Success)
                {
                    ps.Error = new Exception("Непонятная ссылка для комментирования в ЖЖ: " + bp.Link);
                    Log(ps.Error.Message);
                    return ps;
                }
                string itemid = m.Groups[1].ToString();
                //2) откроем страницу комментирования
                sCookie = "adult_concepts=1; adult_explicit=1;";

                HttpWebRequest myHttpWebRequest = MakeRequest("http://"+bp.Link.Host+bp.Link.AbsolutePath+"?mode=reply");
                myHttpWebRequest.Method = "GET";
                myHttpWebRequest.AllowAutoRedirect = false;
                myHttpWebRequest.Referer = "https://www.livejournal.com/";
                HttpWebResponse myHttpWebResponse = (HttpWebResponse)myHttpWebRequest.GetResponse();
                //получаем ответ
                string result = new StreamReader(myHttpWebResponse.GetResponseStream(), Encoding).ReadToEnd();
                myHttpWebResponse.Close();

                //3) Надем нужные вещи...
                //3.1) название блога
                Regex eJournal = new Regex(@"name\W{2}journal\W[^>]*?value\W{2}([^'""]*?)\W", Regexoptions);
                m = eJournal.Match(result);
                if (!m.Success)
                {
                    ps.Error = new Exception("LJ:IComments: Не удалось определить имя блога по ссылке - " + bp.Link);
                    Log(ps.Error.Message);
                    return ps;
                }
                bp.SpecialParam = m.Groups[1].ToString();
                //3.2) ключ для пароля
                Regex eChal = new Regex(@"name.{2}chal\W[^>]*?value\W{2}([^'""]*?)[""']", Regexoptions);
                m = eChal.Match(result);
                if (!m.Success)
                {
                    ps.Error = new Exception("Попытка сделать комментарий не удалась, не найден номер CHAL");
                    Log(ps.Error.Message);
                    return ps;
                }
                string chal = m.Groups[1].Value;
                Regex eChrp1 = new Regex(@"name.{2}chrp1\W[^>]*value\W{2}([^'""]*)[""']", Regexoptions);
                m = eChrp1.Match(result);
                if (!m.Success)
                {
                    ps.Error = new Exception("Попытка сделать комментарий не удалась, не найден номер Chrp1");
                    Log(ps.Error.Message);
                    return ps;
                }
                //chrp1
                string chrp1 = m.Groups[1].Value;
                
                //4) making post here
                myHttpWebRequest = MakeRequest("https://www.livejournal.com/talkpost_do.bml");
                myHttpWebRequest.Method = "POST";
                myHttpWebRequest.Referer = bp.Link.ToString();
                myHttpWebRequest.ContentType = "application/x-www-form-urlencoded";
                ///////////////////////////
                myHttpWebRequest.AllowAutoRedirect = false;
                // передаем параметры
                string sQueryString = String.Format("chal={0}&chrp1={8}&usertype=user&userpost={1}&password={2}&replyto=0&parenttalkid=0&editid=0&itemid={3}&subject={4}" +
                    "&body={5}&subjecticon=none&journal={6}&stylemine=&oidurl=&json=0&talkpost_do=0&response={7}",
                    chal, user.username, user.password, itemid,
                    bp.SubjectUrlEnc,//не работает больше заголовок у комментов(!), а может и работает вроде вернули
                    bp.BodyUrlEnc,
                    bp.SpecialParam,
                    "",//MakePwdMd5(user.password,m.Groups[1].ToString()),
                    chrp1
                    );
                //***************//
                byte[] byteArr = Encoding.GetBytes(sQueryString);
                myHttpWebRequest.ContentLength = byteArr.Length;
                myHttpWebRequest.GetRequestStream().Write(byteArr, 0, byteArr.Length);
                myHttpWebResponse = (HttpWebResponse)myHttpWebRequest.GetResponse();
                //получаем ответ
                result = new StreamReader(myHttpWebResponse.GetResponseStream(), Encoding).ReadToEnd();
                myHttpWebResponse.Close();
                ////////////////////
                //HREF="http://vicniksor.livejournal.com/1586.html?view=1586#t1586">here</A>
                Regex gettinglink = new Regex(@"<a href\W{2}([^'""]+/" + itemid + @"\.html\Wview[^'""]+)\W", Regexoptions);
                m = gettinglink.Match(result);
                //проверим.а не в сообщество ли постим и не получили ли сообщение о необходимости вступить в сообщество..
                if (!m.Success &&
                    String.Compare(bp.SpecialParam, user.username, true) != 0//постим не себе
                    && result.Contains("you are not a member of ")
                    && result.Contains("and commenting is restricted to members only")
                    )
                {
                    JoinCommunnity(user, bp.SpecialParam);
                    Thread.Sleep(2000);
                    //4) making post here
                    myHttpWebRequest = MakeRequest("https://www.livejournal.com/talkpost_do.bml");
                    myHttpWebRequest.Method = "POST";
                    myHttpWebRequest.Referer = bp.Link.ToString();
                    myHttpWebRequest.ContentType = "application/x-www-form-urlencoded";
                    ///////////////////////////
                    myHttpWebRequest.AllowAutoRedirect = false;
                    myHttpWebResponse = (HttpWebResponse)myHttpWebRequest.GetResponse();
                    //получаем ответ
                    result = new StreamReader(myHttpWebResponse.GetResponseStream(), Encoding).ReadToEnd();
                    myHttpWebResponse.Close();
                    m = gettinglink.Match(result);//повторно(!)
                }

                if (m.Success)
                {
                    ps.sLink = new Uri(HttpUtility.UrlDecode(m.Groups[1].ToString()));
                    ps.Error = null;
                    bp.Existance = true;
                }
                else if (result.Contains(">Comment Posted"))//новая фишка, так как наш коммент содержал ссылку
                {
                    ps.Error = null;
                    bp.Existance = true;
                    ps.sLink = null;//комментарий добавлен, но вот ссылку -то нам и не дали =(((
                }
                else
                {
                    ps.Error = new Exception("Не удалось найти ссылку на опубликованный коммент. =(");
                    bp.Existance = false;
                    Log("Не удалось найти ссылку на опубликованный коммент. =(");
                }         
            }
            catch (Exception we)
            {
                Log("MakeComment WebError: " + we.Message);
                ps.Error = we;
            }
            //
            return ps;
        }

        /// <summary> 
        /// Реализует $response = md5($chal.md5($pass));
        /// </summary>
        /// <param name="pwd"></param>
        /// <param name="chal"></param>
        /// <returns></returns>
        private string MakePwdMd5(string pwd, string chal)
        {
            return GetMd5Hash(chal + GetMd5Hash(pwd));
        }

        private string GetMd5Hash(string input)
        {
            MD5CryptoServiceProvider x = new MD5CryptoServiceProvider();
            byte[] bs = Encoding.GetBytes(input);
            bs = x.ComputeHash(bs);
            StringBuilder s = new StringBuilder();
            foreach (byte b in bs)
            {
                s.Append(b.ToString("x2").ToLower());
            }
            return s.ToString();
        }

        /// <summary>
        /// Залогинивание пользователя в ЖЖ
        /// Однако для постинга-комментинга она не используется
        /// </summary>
        /// <param name="user"></param>
        /// <returns></returns>
        public override bool LogInto(UserAccount user)
        {
            if (_isLoggedIn) return true;
            /*HttpWebRequest myHttpWebRequest = MakeRequest("http://www.livejournal.com/login.bml?nojs=1");
            myHttpWebRequest.Method = "GET";
            myHttpWebRequest.Referer = "http://www.livejournal.com/";

            HttpWebResponse myHttpWebResponse = (HttpWebResponse)myHttpWebRequest.GetResponse();
            //получаем ответ
            string result = new StreamReader(myHttpWebResponse.GetResponseStream(), Encoding).ReadToEnd();
            myHttpWebResponse.Close();
            _userId = GetFormAuth(result);*/
            //chal
            /*Regex eChal = new Regex(@"name.{2}chal\W[^>]*?value\W{2}([^'""]*)\W", Regexoptions);
            Match m = eChal.Match(result);
            if (!m.Success)
            {
                Log("Попытка залогинивания не удалась, не найден номер CHAL");
                return false;
            }*/

            HttpWebRequest myHttpWebRequest = MakeRequest("https://www.livejournal.com/login.bml?nojs=1");
            myHttpWebRequest.Method = "POST";
            myHttpWebRequest.Referer = "https://www.livejournal.com/";
            myHttpWebRequest.ContentType = "application/x-www-form-urlencoded";
            ///////////////////////////
            myHttpWebRequest.AllowAutoRedirect = false;
            // передаем параметры
            //string sQueryString = String.Format("response={0}&chal={1}&lj_form_auth={2}&user={3}&password=", 
            string sQueryString = String.Format("user={0}&password={1}", 
              //  MakePwdMd5(user.password, m.Groups[1].ToString()),
               // HttpUtility.UrlEncode(m.Groups[1].ToString()),
                user.username,
                user.password
                );
            //***************//
            byte[] byteArr = Encoding.GetBytes(sQueryString);
            myHttpWebRequest.ContentLength = byteArr.Length;
            myHttpWebRequest.GetRequestStream().Write(byteArr, 0, byteArr.Length);
            HttpWebResponse myHttpWebResponse = (HttpWebResponse)myHttpWebRequest.GetResponse();
            //получаем ответ
#if DEBUG
            string result = new StreamReader(myHttpWebResponse.GetResponseStream(), Encoding).ReadToEnd();
#endif
            myHttpWebResponse.Close();
            if (!String.IsNullOrEmpty(myHttpWebResponse.Headers[HttpResponseHeader.SetCookie]))
            {
                //должны были получить ответ с нужными куками
                CookieParse(myHttpWebResponse.Headers[HttpResponseHeader.SetCookie]);
                //стираем куку привязки к определенному домену.
                sCookie = new Regex(@"ljdomsess\.[^;]+(?:;|$)", Regexoptions).Replace(sCookie, "");
                Log("LogInto " + user + " gains cookie = " + sCookie);
            }
            //
            _isLoggedIn = !String.IsNullOrEmpty(sCookie) && sCookie.Contains("ljsession") 
                && sCookie.Contains("ljloggedin") && sCookie.Contains("ljmastersession");
            if (_isLoggedIn)
            {
                LoggedInAs = user;
            }
            return _isLoggedIn;
        }

        #endregion

        #region interface: IFriends

        /// <summary>
        /// Функция вступления в сообщество.
        /// </summary>
        /// <param name="who">кто вступает</param>
        /// <param name="communityName">куда вступает</param>
        /// <returns>Ошибку, если таковая имела место, иначе NULL</returns>
        public Exception JoinCommunnity(UserAccount who, string communityName)
        {
            try
            {
                //залогиниваемся
                //logging
                if (!LogInto(who))
                {
                    throw new Exception("Не удалось залогинится");
                }
                string joinUrl = "https://www.livejournal.com/community/join.bml?comm=" + communityName.Replace("-", "_");
                //уже залогинилися...
                HttpWebRequest myHttpWebRequest =
                    MakeRequest(joinUrl);
                myHttpWebRequest.Method = "GET";
                HttpWebResponse myHttpWebResponse = (HttpWebResponse)myHttpWebRequest.GetResponse();
                //получаем ответ
                string result = new StreamReader(myHttpWebResponse.GetResponseStream(), 
                    Encoding).ReadToEnd();
                myHttpWebResponse.Close();
                //теперь парсим ответ
                if (String.IsNullOrEmpty(result))
                {
                    throw new Exception("Получен пустой ответ.");
                }
                //addfriend=0 // нем не нужно его читать.
                //lj_form_auth
                _userId = GetFormAuth(result);
                myHttpWebRequest = MakeRequest(joinUrl);
                myHttpWebRequest.Method = "POST";
                myHttpWebRequest.Referer = joinUrl;
                myHttpWebRequest.ContentType = "application/x-www-form-urlencoded";
                ///////////////////////////
                myHttpWebRequest.AllowAutoRedirect = false;
                // передаем параметры
                string sQueryString = String.Format("addfriend=1&lj_form_auth={0}",
                                                    HttpUtility.UrlEncode(_userId)
                    );
                //***************//
                byte[] byteArr = Encoding.GetBytes(sQueryString);
                myHttpWebRequest.ContentLength = byteArr.Length;
                myHttpWebRequest.GetRequestStream().Write(byteArr, 0, byteArr.Length);
                myHttpWebResponse = (HttpWebResponse)myHttpWebRequest.GetResponse();
                //получаем ответ
#if DEBUG
                result = new StreamReader(myHttpWebResponse.GetResponseStream(), this.Encoding).ReadToEnd();
#endif
                myHttpWebResponse.Close();

                return null;
            }
            catch (Exception e1)
            {
                Log("JoinCommunnity: " + e1.Message);
                return e1;
            }
        }

        /// <summary>
        /// Функция покидания сообщества.
        /// </summary>
        /// <param name="who">кто вступает</param>
        /// <param name="communityName">куда вступает</param>
        /// <returns>Ошибку, если таковая имела место, иначе NULL</returns>
        public Exception LeaveCommunnity(UserAccount who, string communityName)
        {
            try
            {
                //залогиниваемся
                //logging
                if (!LogInto(who))
                {
                    throw new Exception("Не удалось залогинится");
                }
                string joinUrl = "https://www.livejournal.com/community/leave.bml?comm=" + communityName.Replace("-", "_");
                //уже залогинилися...
                HttpWebRequest myHttpWebRequest =
                    MakeRequest(joinUrl);
                myHttpWebRequest.Method = "GET";
                HttpWebResponse myHttpWebResponse = (HttpWebResponse)myHttpWebRequest.GetResponse();
                //получаем ответ
                string result = new StreamReader(myHttpWebResponse.GetResponseStream(),
                    Encoding).ReadToEnd();
                myHttpWebResponse.Close();
                //теперь парсим ответ
                if (String.IsNullOrEmpty(result))
                {
                    throw new Exception("Получен пустой ответ.");
                }
                //addfriend=0 // нем не нужно его читать.
                //lj_form_auth
                _userId = GetFormAuth(result);
                myHttpWebRequest = MakeRequest(joinUrl);
                myHttpWebRequest.Method = "POST";
                myHttpWebRequest.Referer = joinUrl;
                myHttpWebRequest.ContentType = "application/x-www-form-urlencoded";
                ///////////////////////////
                myHttpWebRequest.AllowAutoRedirect = false;
                // передаем параметры
                string sQueryString = String.Format("comm={1}&lj_form_auth={0}&confirm=1&removefriend=1",
                                                    HttpUtility.UrlEncode(_userId),
                                                    communityName.Replace("-", "_")
                    );
                //***************//
                byte[] byteArr = Encoding.GetBytes(sQueryString);
                myHttpWebRequest.ContentLength = byteArr.Length;
                myHttpWebRequest.GetRequestStream().Write(byteArr, 0, byteArr.Length);
                myHttpWebResponse = (HttpWebResponse)myHttpWebRequest.GetResponse();
                //получаем ответ
                //result = new StreamReader(myHttpWebResponse.GetResponseStream(), this.Encoding).ReadToEnd();
                myHttpWebResponse.Close();

                return null;
            }
            catch (Exception e1)
            {
                Log("JoinCommunnity: " + e1.Message);
                return e1;
            }
        }

        /// <summary>
        /// Интерфейс по добавлению френдов
        /// </summary>
        /// <param name="who">Имя аккаунта для которого меняем френдов</param>
        /// <param name="friends">Набор имен аккаунтов для френдования</param>
        /// <returns>NULL, если все хорошо, иначе ошибку ввиде Exception</returns>
        /// <remarks>
        /// 	global $user,$ljlink,$lj_form_auth;
	    ///$param = "remoteuser=$user&lj_form_auth=$lj_form_auth&commands=";
	    ///if(is_array($friends)){
	    ///	foreach ($friends as $fr){
	    ///$param .= urldecode("friend add ".rtrim($fr)."\n");
	    ///}
	    ///}
	    ///$reply = sendToHost($ljlink,"POST","/admin/console/",$param,$cookie);
	    ///return ;
        /// </remarks>
        public override List<String> AddFriends(UserAccount who, params string[] friends)
        {
            List<String> oRet = new List<string>(0);
            try
            {
                BasicFriendsVerify(who,friends);
                ProcessConsole("add", friends);
                return null;
            }
            catch (Exception e1)
            {
                oRet.Add(e1.Message);
            }
            return oRet;
            
        }

        /// <summary>
        /// Интерфейс по удалению френдов
        /// </summary>
        /// <param name="who">Имя аккаунта для которого меняем френдов</param>
        /// <param name="friends">Набор имен аккаунтов для френдования</param>
        /// <returns>NULL, если все хорошо, иначе ошибку ввиде Exception</returns>
        public override List<String> DelFriends(UserAccount who, params string[] friends)
        {
            List<String> oRet = new List<string>(0);
            try
            {
                BasicFriendsVerify(who, friends);
                ProcessConsole("remove", friends);                
                return null;
            }
            catch (Exception e1)
            {
                oRet.Add(e1.Message);
            }
            return oRet;
        }

        private void BasicFriendsVerify(UserAccount who, string[] friends)
        {
            if (friends == null || friends.Length == 0)
            {
                throw new Exception("Не задан список друзей");
            }
            if (friends.Length > 200)
            {
                throw new Exception("Нельзя редактировать больше 200 френдов за раз");
            }
            if (!LogInto(who))
            {
                throw new Exception("Не удалось залогиниться под аккаунтом " + who.ToString());
            }
        }

        /// <summary>
        /// Передача команды в консоль ЖЖ
        /// </summary>
        /// <param name="command">add or remove</param>
        /// <param name="friends">список френдов</param>
        private void ProcessConsole(string command, string [] friends)
        {
            HttpWebRequest myHttpWebRequest = MakeRequest("https://www.livejournal.com/admin/console/");
            myHttpWebRequest.Method = "GET";
            myHttpWebRequest.Referer = "https://www.livejournal.com/";
            HttpWebResponse myHttpWebResponse = (HttpWebResponse)myHttpWebRequest.GetResponse();
            //получаем ответ
            string result = new StreamReader(myHttpWebResponse.GetResponseStream(), Encoding).ReadToEnd();
            myHttpWebResponse.Close();
            //lj_form_auth
            _userId = GetFormAuth(result);
            /////////////////
            myHttpWebRequest = MakeRequest("https://www.livejournal.com/admin/console/index.bml");
            myHttpWebRequest.Method = "POST";
            myHttpWebRequest.Referer = "https://www.livejournal.com/admin/console/index.bml";
            myHttpWebRequest.ContentType = "application/x-www-form-urlencoded";
            ///////////////////////////
            myHttpWebRequest.AllowAutoRedirect = false;
            // передаем параметры
            string sQueryString = String.Format("remoteuser={0}&lj_form_auth={1}&commands={2}",
                LoggedInAs.username, 
                HttpUtility.UrlEncode(_userId)/*lj_form_auth*/,
                HttpUtility.UrlEncode("friend " + command + " " + 
                String.Join("\nfriend " + command + " ", friends) + "\n"));
            //***************//
            byte[] byteArr = Encoding.GetBytes(sQueryString);
            myHttpWebRequest.ContentLength = byteArr.Length;
            myHttpWebRequest.GetRequestStream().Write(byteArr, 0, byteArr.Length);
            
            myHttpWebResponse = (HttpWebResponse)myHttpWebRequest.GetResponse();
            //получаем ответ
            //result = new StreamReader(myHttpWebResponse.GetResponseStream(), this.Encoding).ReadToEnd();
            myHttpWebResponse.Close();
        }

        #endregion

        #region interface: IData Функционал экспорта данных

        /// <summary>
        /// Получение ссылки на RSS блогера
        /// </summary>
        /// <param name="userName">ник блогера</param>
        /// <param name="btype">Тип блога - сообщество или блог</param>
        /// <remarks>Неработает если имя пользователя русское, тогда нужен номер</remarks>
        public override String GetRssLink(string userName, BlogType btype)
        {
            return GetBlogLink(userName, btype) + "/data/rss";
        }

        /// <summary>
        /// Получение ссылки на FOAF блогера
        /// </summary>
        /// <param name="userName">ник блогера</param>
        /// <param name="btype">Тип блога - сообщество или блог</param>
        /// <remarks>Неработает если имя пользователя русское, тогда нужен номер</remarks>
        public override String GetFoafLink(string userName, BlogType btype)
        {
            return GetBlogLink(userName, btype) + "/data/foaf";
        }

        /// <summary>
        /// Извлечение картинки пользователя
        /// </summary>
        /// <param name="userName">имя блогера</param>
        /// <param name="btype">тип блога</param>
        /// <returns>Прямая ссылка на картинку</returns>
        public override string ExtractAvatar(string userName, BlogType btype)
        {
            try
            {
                RdfDocument foaf = ParseFoaf(userName, btype);
                if (foaf != null && foaf.Who.Images != null && foaf.Who.Images.Length > 0)
                {
                    return foaf.Who.Images[0].Resource;
                }
            }
            catch(XmlException e0)
            {
                try
                {
                    var rss = RssDocument.Load(new Uri(GetRssLink(userName, btype)), true);
                    return (rss.Channel?.Image?.Url) ?? String.Empty;
                }
                catch (Exception e2)
                {
                    Debug.WriteLine("Ошибка получения FOAF файла:" + e2.Message);
                }
            }
            catch (Exception e1)
            {
                Debug.WriteLine("Ошибка получения FOAF файла:"+e1.Message);
            }
            return String.Empty;
        }

        #endregion

        #region Функционал отвечающий за OpenID

        /// <summary>
        /// Проверка, является ли адресс запросом на openid.
        /// </summary>
        /// <param name="url"></param>
        /// <returns></returns>
        public override bool IsOpenIDRequest(string url)
        {
            return !String.IsNullOrEmpty(url)&&
                new Regex(@"livejournal\.com/openid").Match(url).Success;
        }

        /// <summary>
        /// Обработка запроса на openid
        /// </summary>
        /// <param name="url">ссылка запроса</param>
        /// <param name="user">пользователь</param>
        /// <returns>Ссылка для возвращения в сторонний сервис</returns>
        public override string GrantOpenID(string url, UserAccount user)
        {
            if (!IsOpenIDRequest(url)) return null;
            if (user != LoggedInAs && !LogInto(user))//еще не логинились и не удалось залогиниться
            {
                throw new Exception("Cant login into " + user);
            }
            try
            {
                HttpWebRequest myHttpWebRequest = MakeRequest(url);
                myHttpWebRequest.AllowAutoRedirect = false;
                HttpWebResponse myHttpWebResponse = (HttpWebResponse) myHttpWebRequest.GetResponse();
                //получаем ответ
                string result;// = new StreamReader(myHttpWebResponse.GetResponseStream(), Encoding).ReadToEnd();
                myHttpWebResponse.Close();
                if (myHttpWebResponse.StatusCode == HttpStatusCode.Found)
                {
                    url = myHttpWebResponse.Headers[HttpResponseHeader.Location];
                    myHttpWebRequest = MakeRequest(url);
                    myHttpWebRequest.AllowAutoRedirect = false;
                    myHttpWebResponse = (HttpWebResponse) myHttpWebRequest.GetResponse();
                    //получаем ответ
                    result = new StreamReader(myHttpWebResponse.GetResponseStream(), Encoding).ReadToEnd();
                    myHttpWebResponse.Close();
                    //теперь нужно нажать кнопку подтверждения залогинивания.
                    myHttpWebRequest = MakeRequest(url);
                    myHttpWebRequest.Method = "POST";
                    myHttpWebRequest.Referer = "https://www.livejournal.com/";
                    myHttpWebRequest.ContentType = "application/x-www-form-urlencoded";
                    ///////////////////////////
                    myHttpWebRequest.AllowAutoRedirect = false;
                    // передаем параметры
                    string sQueryString =
                        String.Format("lj_form_auth={0}&submit=" + HttpUtility.UrlEncode("Yes; always."),
                                      HttpUtility.UrlEncode(GetFormAuth(result))
                            );
                    //***************//
                    byte[] byteArr = Encoding.GetBytes(sQueryString);
                    myHttpWebRequest.ContentLength = byteArr.Length;
                    myHttpWebRequest.GetRequestStream().Write(byteArr, 0, byteArr.Length);
                    myHttpWebResponse = (HttpWebResponse) myHttpWebRequest.GetResponse();
                    //получаем ответ
                    //result = new StreamReader(myHttpWebResponse.GetResponseStream(), Encoding).ReadToEnd();
                    myHttpWebResponse.Close();
                    //return myHttpWebResponse;
                    return myHttpWebResponse.Headers[HttpResponseHeader.Location];
                }
            }catch(Exception e1)
            {
                Log("LJ:OpenID Error: "+e1.Message);
            }
            return null;
        }

        #endregion

        #region IQuote

        /// <summary>
        /// Получение сслки для цитирования по посту
        /// </summary>
        /// <param name="bp">Заполненный объект с постом</param>
        /// <returns>ссылку на страницу цитирования, NULL если цитирование не возможно</returns>
        /// <remarks>https://www.livejournal.com/update.bml?event=text</remarks>
        public String GetQuoteLink(BlogPost bp)
        {
            if (String.IsNullOrEmpty(bp.Body)) return "";
            string text = bp.Body.Length > 300 ? bp.Body.Substring(0, 300):bp.Body;
            text = "<blockquote>" + text + "</blockquote>";
            if(bp.Link!=null)
            {
                text = "<a href='" + bp.Link.OriginalString+"'>Цитата:</a>";
            }
            return "https://www.livejournal.com/update.bml?event=" +
                   HttpUtility.UrlEncode(text);
        }

        #endregion

        /// <summary>
        /// Функция получения списка блогеров по известному интересу
        /// </summary>
        /// <param name="sInt">Название интереса для извлечения</param>
        /// <returns></returns>
        public List<String> GetBloggersByInterest(string sInt)
        {
            var blogs = new List<String>(0);
            //вообще все найденные блоги
            var all_blogs = new List<String>(0);
            try{
                int pagemax = 50;
                var eNames = new Regex(@"<a\s+href\W+allpics\.bml\?user=([a-z0-9_]+)\W.*?<td.*?class\W+lastupdated[^>]+>[^<\d]+?(\d*)[^<\d]+<", Regexoptions);
                for (int pageNumber = 1; pageNumber < pagemax; pageNumber++)
                {
                    String url = String.Format("https://www.livejournal.com/interests.bml?int={0}&page={1}",
                                               HttpUtility.UrlEncode(sInt), pageNumber);
                    HttpWebRequest myHttpWebRequest = MakeRequest(url);
                    myHttpWebRequest.Method = "GET";
                    HttpWebResponse myHttpWebResponse = (HttpWebResponse) myHttpWebRequest.GetResponse();
                    //получаем ответ
                    string result = new StreamReader(myHttpWebResponse.GetResponseStream(),
                                                     Encoding).ReadToEnd();
                    myHttpWebResponse.Close();
                    //теперь парсим ответ
                    MatchCollection mc = eNames.Matches(result);
                    if(mc.Count>0)
                    {
                        foreach (Match match in mc)
                        {
                            if (all_blogs.Contains(match.Groups[1].Value))//уже есть, дошли до конца
                            {
                                pageNumber = pagemax;
                                break;
                            }
                            //вообще все найденные
                            all_blogs.Add(match.Groups[1].Value);
                            if(String.IsNullOrEmpty(match.Groups[2].Value)//никогда не обновлялся
                                || int.Parse(match.Groups[2].Value)>=60)//больше 60 недель назад
                            {
                                break;
                            }
                            //Добавляем в общюю выдачу
                            blogs.Add(match.Groups[1].Value);
                        }
                    }else{
                        break;
                    }
                }
            }
            catch (Exception e1)
            {
                Log("GetBloggersByInterest: " + e1.Message);
            }
            return blogs;
        }
    }
}


